using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sixeyed.CacheAdapter.NCacheExpressProvider.Tests.Stubs;
using System.Threading;
using Sixeyed.CacheAdapter.NCacheExpressProvider.Tests.Properties;

namespace Sixeyed.CacheAdapter.NCacheExpressProvider.Tests.Fixtures
{
    [TestClass]
    public class NCacheExpressProviderTest
    {
        private NCacheExpressProvider _provider;
        private NCacheExpressProvider Provider
        {
            get
            {
                if (_provider == null)
                {
                    _provider = new NCacheExpressProvider();

                    NCacheExpressProviderConfiguration config = new NCacheExpressProviderConfiguration();
                    config.CacheId = "Sixeyed.CacheAdapter.NCacheExpressProvider.Tests";
                    config.DefaultLifespan = new TimeSpan(0, 1, 5);

                    _provider.Initialize(config);
                }
                return _provider;
            }
        }

        [TestMethod]
        public void Initialize()
        {
            Assert.IsTrue(this.Provider.IsInitialized);
        }

        [TestMethod]
        public void Put_KnownKey()
        {
            TimeSpan lifespan1 = new TimeSpan(0, 10, 0);
            StubEntity stub1 = new StubEntity();
            stub1.Id = 1;
            stub1.Name = "Known StubEntity";
            stub1.CreatedDate = DateTime.Now;
            string cacheKey1 = "9536DA27-0281-4a81-9BC5-6B1B781B7637";
            Provider.Put(cacheKey1, stub1, lifespan1);
            Assert.IsTrue(true, "Insert failed");
        }

        [TestMethod]
        public void PutThenGet()
        {
            TimeSpan lifespan1 = new TimeSpan(0, 0, 1);
            StubEntity stub1 = new StubEntity();
            stub1.Id = 1;
            stub1.Name = "StubEntity One";
            stub1.CreatedDate = DateTime.Now;
            string cacheKey1 = Provider.GetCacheKey();
            Provider.Put(cacheKey1, stub1, lifespan1);
            Assert.IsTrue(true, "Insert failed");
            Provider.Put(cacheKey1, stub1, lifespan1);
            Assert.IsTrue(true, "Duplicate insert failed");
            TimeSpan lifespan2 = new TimeSpan(0, 0, 20);
            StubEntity stub2 = new StubEntity();
            stub2.Id = 2;
            stub2.Name = "StubEntity Two";
            stub2.CreatedDate = DateTime.Now;
            string cacheKey2 = Provider.GetCacheKey();
            Provider.Put(cacheKey2, stub2, lifespan2);
            Assert.IsTrue(true, "Insert failed");
            //check retrieval:
            StubEntity cached1 = Provider.Get<StubEntity>(cacheKey1);
            Assert.IsNotNull(cached1, "Get failed");
            StubEntity cached2 = Provider.Get<StubEntity>(cacheKey2);
            Assert.IsNotNull(cached2, "Get failed");
            //check expiry:
            Thread.Sleep(new TimeSpan(0, 0, 3));
            cached1 = Provider.Get<StubEntity>(cacheKey1);
            Assert.IsNull(cached1, "Expiry failed");
            cached2 = Provider.Get<StubEntity>(cacheKey2);
            Assert.IsNotNull(cached2, "Get failed");
        }

        [TestMethod]
        public void GetCacheKey()
        {
            string request1 = Resources.SampleService_Request1;
            string request2 = Resources.SampleService_Request2;

            string requestKey1 = Provider.GetCacheKey(request1);
            string requestKey2 = Provider.GetCacheKey(request2);

            Assert.AreNotEqual(requestKey1, requestKey2);
        }

        [TestMethod]
        public void RequestResponse()
        {
            string request = Resources.SampleService_Request1;
            string requestKey = Provider.GetCacheKey(request);

            string response = Resources.SampleService_Response1;
            Provider.Put(requestKey, response);

            string cached = Provider.Get<string>(requestKey);

            Assert.AreEqual(response, cached);
        }

        [TestMethod]
        public void MultiThreadedPut()
        {
            List<string> keys = new List<string>();
            string response = Resources.SampleService_Response1;
            for (int i = 0; i < 20; i++)
            {
                CacheEntry entry = new CacheEntry();
                entry.Key = Provider.GetCacheKey();
                entry.Value = response;
                keys.Add(entry.Key);
                ThreadPool.QueueUserWorkItem(new WaitCallback(this.CacheInsert), entry);
            }
            //wait for threads to finish:
            Thread.Sleep(new TimeSpan(0, 0, 5));
            int index = 0;
            foreach (string key in keys)
            {
                string cached = Provider.Get<string>(key);
                Assert.AreEqual(response, cached, "Get failed, index={0}:", index);
                index++;
            }
        }

        private void CacheInsert(object args)
        {
            CacheEntry entry = (CacheEntry)args;
            Provider.Put(entry.Key, entry.Value);
        }

        private struct CacheEntry
        {
            public string Key;
            public object Value;
        }
    }
}

